#ifndef InclusionGuard_SoundPotVstInstrument_h
#define InclusionGuard_SoundPotVstInstrument_h

#include "pluginterfaces/vst2.x/aeffectx.h"
#include <string>

// Following construct avoids some name conflicts between windows.h and juce.h
#if _WIN32
#undef Rectangle
#undef T
#define Array tempArray
#include <windows.h>
#undef Array
#define T(x) L#x 
#endif

#include "SoundPotInstrument.h"

namespace SoundPot
{
	class VstInstrument : public Instrument
	{

	public:

		/// Used in MyVstEvents
		static const int MAX_MIDI_EVENTS_PER_AUDIO_BUFFER = 100;

		/*  Define a type, which represents the signature
			of the HostCallback function. In this case it is only
			a simple "wrapper" around the audioMasterCallback type,
			which is provided by Steinberg.
		*/


		typedef audioMasterCallback TypeHostCallbackFunction;

		/// An enumeration for can-do queries

		enum CanDoAnswer
		{
			no,
			yes,
			unsure
		};

		/// Adapted VstEvents struct
		// This one can take more than two events in oposit to the original VstEvents struct defined in aeffectx.h.
		// (Why is this necessary? Sometimes VST interface code can be quite strange!)
		struct MyVstEvents
		{
			VstInt32 numEvents;
			VstIntPtr reserved;
			VstEvent* events[MAX_MIDI_EVENTS_PER_AUDIO_BUFFER]; // That's the point
		};

		/// A structure for VST parameters
		struct Parameter
		{
			std::string Name;
			std::string Label;
			std::string Display;
			float Value;
		};

		struct Program
		{
			std::string Name;
		};

		/// Constructor, which automatically loads and opens the specified plugin
		VstInstrument();

		/// Destructor, which automatically closes and unloads the plugin
		~VstInstrument();

		void setModulePath(const std::string& path);


		/// The real, object oriented vstHostCallback() function.
		// VSTCALLBACK is AFAIK only a platform independent name for a calling convention (like __cdecl on Win32)
		VstIntPtr VSTCALLBACK pluginToHostCallback (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt);


		/// Static host callback
		/*	That one is needed by VST Plugins to send messages to the host.
			Unfortunately, it's not possible to let a VST Plugin directly call the real object method
			vstHostCallback() because a VST Plugin needs a normal function pointer and doesn't accept a method pointer.
			So I introduced additionally staticVstHostCallback() as a static function, that means it will be called in 
			a global context rather than in an object context.
			The implementation of this function doesn't do anything else than forwarding the function call to
			a real method, called in an object context.
		*/
		static VstIntPtr VSTCALLBACK staticPluginToHostCallback (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt);


		//	Implementation of Instrument methods

		void load();

		void unload();

		void control(VstEvents* events);

		void showEditor();

		void loadAssignedSound();

		void suspend();

		void wakeUp();

		void setSampleRate(const float& value);

		void setMaxBlockSize(const int& value);
		
		void fillNextAudioBlock(float** inputChannels, float** outputChannels, const VstInt32 blockSize);

		


		/// Gets the effect's number of parameters
		const VstInt32 getNumberOfParameters();

		/// Gets the effect's number of inputs
		const VstInt32 getNumberOfInputs();

		/// Gets the effect's number of outputs
		const VstInt32 getNumberOfOutputs();

		/// Gets the parameter at the specified index
		const Parameter getParameterAt(const VstInt32 index);


		/// The most important method: Processes audio data
		void process(float** inputChannels, float** outputChannels, const VstInt32 numSampleFrames);

		






	private:
		
		/// Holds the path to the dll or whatever module format is used
		std::string modulePath;

		/// Process e.g. MIDI events
		void processEvents(VstEvents* events);		

		/// Returns whether the effect has the specified feature
		const CanDoAnswer canDo(const std::string& feature);

		/// Returns whether the effect provides an own editor
		const bool hasEditor();
		
		/// Gets the program at the specified index
		const Program getProgramAt(const VstInt32 index);

		/// Gets the effect's name
		const std::string getName();

		/// Gets the effect's vendor string
		const std::string getVendorString();

		/// Gets the effect's product string
		const std::string getProductString();

		/// Gets the effect's number of programs
		const VstInt32 getNumberOfPrograms();



		/// Holds the module (in Windows this is the library of the VST plugin)
		// module is void, because its actual type (for example HINSTANCE) is platform dependent
		void* module;

		/// Holds the AEffect instance, that shall be wrapped
		// effects should be put on the heap
		AEffect* effect;

		/// Loads the library and creates a AEffect instance
		void load(TypeHostCallbackFunction hostCallback, const std::string& pathToPluginDll);



		/// Opens the effect for usage
		void open();

		/// Closes the effect. That includes removing it from heap. So after this is called, the effect shouldn't be used anymore.
		void close();




		/// EditorProcess function for GUI
		static INT_PTR CALLBACK EditorProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);


		/// For GUI
		struct MyDLGTEMPLATE: DLGTEMPLATE
		{
			WORD ext[3];
			MyDLGTEMPLATE ()
			{
				memset (this, 0, sizeof (*this));
			};
		};
	};

	/// For GUI
	static AEffect* theEffect;
}


#endif